﻿using Renci.SshNet;
using System;

namespace CommonUtils
{
    public static class SshUtil
    {
        public static SshClient CreateClient(string host, string user, string pwd, double timeoutSeconds = 3.3)
        {
            var client = new SshClient(host, user, pwd);
            client.ConnectionInfo.Timeout = TimeSpan.FromSeconds(timeoutSeconds);
            return client;
        }

        public static string ExecuteCommand(this SshClient client, string command)
        {
            client.Connect();
            var commander = client.CreateCommand(command);
            var result = commander.Execute();
            client.Disconnect();
            return result;
        }

        public static string GetIpConfig(this SshClient client)
        => client.ExecuteCommand("ifconfig");

        public static void PrintIpConfig(this SshClient client)
        => client.GetIpConfig().Print();

        public static SshConnectState TryConnect(this SshClient client, string displayPassword = "[hidden]")
        {
            LogUtil.PrintInfo("SshClient is trying to connect to {0} with user {1} and pwd {2}.",
                          client.ConnectionInfo.Host,
                          client.ConnectionInfo.Username,
                          displayPassword);
            try
            {
                var ipconfig = client.GetIpConfig();
                if (ipconfig.Length > 100)
                {
                    LogUtil.PrintInfo("SshClient connectted success!");
                    return SshConnectState.Success;
                }
                else
                {
                    LogUtil.PrintInfo("SshClient connectted fail!");
                    return SshConnectState.Fail;
                }
            }
            catch (Exception ex)
            {
                LogUtil.PrintInfo(ex.Message);

                var exName = ex.GetType().Name;
                switch (exName)
                {
                    case "SshOperationTimeoutException":
                        return SshConnectState.Timeout;

                    case "SshAuthenticationException":
                        return SshConnectState.AuthenticationDeny;

                    case "SocketException":
                        return SshConnectState.ProtocalDeny;

                    case "SshConnectionException":
                        return SshConnectState.ConnectionException;

                    default:
                        ex.HelpLink = client.ConnectionInfo.Host;
                        LogUtil.Record(ex);
                        return SshConnectState.Unknown;
                }
            }
        }

        public static SshConnectState TryConnect(string host, string user, string pwd, double timeoutSeconds)
        {
            var client = CreateClient(host, user, pwd, timeoutSeconds);
            return client.TryConnect(pwd);
        }

        public static bool CanConnect(this SshClient client, string displayPassword = "[hidden]")
        => client.TryConnect(displayPassword) == SshConnectState.Success;

        public static bool CanConnect(string host, string user, string pwd, double timeoutSeconds)
        => TryConnect(host, user, pwd, timeoutSeconds) == SshConnectState.Success;
    }
}
